<!DOCTYPE html>
<html>
<head>
  <title>Direct Sockets TCP Test</title>
  <script>
    'use strict';

    async function writeLoop(writer, requiredBytes) {
      if (!(writer instanceof WritableStreamDefaultWriter))
        return 'write failed: writer is not a WritableStreamDefaultWriter';
      let bytesWritten = 0;
      let chunkLength = 0;
      while (bytesWritten < requiredBytes) {
        chunkLength = Math.min(chunkLength + 1,
                               requiredBytes - bytesWritten);
        let chunk = new Uint8Array(chunkLength);
        for (let index = 0; index < chunkLength; ++index) {
          chunk[index] = bytesWritten % 256;
          ++bytesWritten;
        }
        await writer.ready;
        await writer.write(chunk);
      }
      return 'write succeeded';
    }

    async function writeTcp(options, requiredBytes) {
      try {
        let tcpSocket = await navigator.openTCPSocket(options);
        let writer = tcpSocket.writable.getWriter();
        return await writeLoop(writer, requiredBytes);
      } catch(error) {
        return ('writeTcp failed: ' + error);
      }
    }

    async function readLoop(reader, requiredBytes) {
      if (!(reader instanceof ReadableStreamDefaultReader))
        return 'read failed: reader is not a ReadableStreamDefaultReader';
      let bytesRead = 0;
      while (bytesRead < requiredBytes) {
        const { value, done } = await reader.read();
        if (done)
          return 'read failed: unexpected stream close';
        if (!value || value.length === 0)
          return 'read failed: no data returned';

        for (let index = 0; index < value.length; ++index) {
          if (value[index] !== bytesRead % 256)
            return 'read failed: bad data returned';
          ++bytesRead;
        }
      }
      return 'read succeeded';
    }

    async function readTcp(options, requiredBytes) {
      try {
        let tcpSocket = await navigator.openTCPSocket(options);
        let reader = tcpSocket.readable.getReader();
        return await readLoop(reader, requiredBytes);
      } catch(error) {
        return ('readTcp failed: ' + error);
      }
    }

    async function readWriteTcp(options, requiredBytes) {
      try {
        let tcpSocket = await navigator.openTCPSocket(options);
        let reader = tcpSocket.readable.getReader();
        let writer = tcpSocket.writable.getWriter();
        let [readResult, writeResult] =
            await Promise.all([readLoop(reader, requiredBytes),
                               writeLoop(writer, requiredBytes)]);
        if (readResult !== 'read succeeded')
          return readResult;
        if (writeResult !== 'write succeeded')
          return writeResult;
        return 'readWrite succeeded';
      } catch(error) {
        return ('readWriteTcp failed: ' + error);
      }
    }

    async function closeTcp(options, closeWriter) {
      try {
        let tcpSocket = await navigator.openTCPSocket(options);
        let writer = tcpSocket.writable.getWriter();
        if (closeWriter)
          await writer.close();
        await tcpSocket.close();
        return 'closeTcp succeeded';
      } catch(error) {
        return ('closeTcp failed: ' + error);
      }
    }

  </script>
</head>
<body>
  <h1>Direct Sockets TCP Test</h1>
</body>
</html>
